﻿Ext.gesture.Manager = new Ext.AbstractManager({

    //底层基本事件名
    eventNames: {
        start: 'touchstart',
        move: 'touchmove',
        end: 'touchend'
    },

    defaultPreventedMouseEvents: ['click'],

    clickMoveThreshold: 5,

    //初始化函数，这个是在Ext.EventManager.onDocumentReady中调用的
    init: function () {
        this.targets = [];

        this.followTouches = [];
        this.currentGestures = [];//当前事件类数组
        this.currentTargets = [];//触发事件的节点数组

        //如果平台不支持触屏，则覆盖基本的事件名
        if (!Ext.supports.Touch) {
            Ext.apply(this.eventNames, {
                start: 'mousedown',
                move: 'mousemove',
                end: 'mouseup'
            });
        }

        //Ext.gesture.Manager统一了底层事件的响应函数
        //pc上的底层事件'mousedown','mousemove','mouseup',
        //移动设备上的是'touchstart','touchmove','touchend'，
        //分别统一成'start','move',end'。
        //共用的是click,统一成'mouse'
        //然后再给他们定义响应函数。
        this.listenerWrappers = {
            start: Ext.createDelegate(this.onTouchStart, this),
            move: Ext.createDelegate(this.onTouchMove, this),
            end: Ext.createDelegate(this.onTouchEnd, this),
            mouse: Ext.createDelegate(this.onMouseEvent, this)
        };

        //将Ext.gesture.Manager的函数注册到底层的基本事件中
        this.attachListeners();
    },

    freeze: function () {
        this.isFrozen = true;
    },

    thaw: function () {
        this.isFrozen = false;
    },

	//获取Ext.util.EventSimulator对象
    getEventSimulator: function () {
        if (!this.eventSimulator) {
            this.eventSimulator = new Ext.util.EventSimulator();
        }

        return this.eventSimulator;
    },

    //将Ext.gesture.Manager的函数注册到底层的基本事件中
    attachListeners: function () {

        //遍历this.eventNames
        Ext.iterate(this.eventNames, function (key, name) {
            //将最基本的事件（移动设备的'touchstart','touchmove','touchend'
            //pc的'mousedown','mousemove','mouseup'）的响应函数注册到document中
            document.addEventListener(name, this.listenerWrappers[key], false);//这是事件机制最低层的注册
        }, this);

        //如果平台支持触屏
        if (Ext.supports.Touch) {
            //给defaultPreventedMouseEvents中的事件（'click'）添加响应函数
            this.defaultPreventedMouseEvents.forEach(function (name) {
                document.addEventListener(name, this.listenerWrappers['mouse'], true);
            }, this);
        }
    },

    //将底层的基本事件移除
    detachListeners: function () {
        Ext.iterate(this.eventNames, function (key, name) {
            document.removeEventListener(name, this.listenerWrappers[key], false);
        }, this);

        if (Ext.supports.Touch) {
            this.defaultPreventedMouseEvents.forEach(function (name) {
                document.removeEventListener(name, this.listenerWrappers['mouse'], true);
            }, this);
        }
    },

    //'click'事件
    onMouseEvent: function (e) {
        if (!e.isSimulated) {
            e.preventDefault();//阻止浏览器默认事件
            e.stopPropagation();//阻止事件传递
        }
    },

    //pc上的'mousedown',移动设备上的'touchstart'的响应函数
    onTouchStart: function (e) {
        var targets = [],
            target = e.target;//触发事件的元素（Mozzilla浏览器）

        if (e.stopped === true) {//事件被阻止，则直接返回
            return;
        }

		//如果是Android平台
        if (Ext.is.Android) {
			//如果触发事件的元素不是input、textarea、select控件
            if (!(target.tagName && ['input', 'textarea', 'select'].indexOf(target.tagName.toLowerCase()) !== -1)) {
                e.preventDefault(); //阻止后面将要执行的浏览器默认动作
            }
        }

        if (this.isFrozen) {//如果事件冻结，直接返回
            return;
        }

        // 触碰事件是否未结束，即还未调用结束事件而又一次触发了触碰事件，则调用结束事件
        if (this.startEvent) {
            this.onTouchEnd(e);
        }

        this.locks = {};

        this.currentTargets = [target]; //触发事件的元素数组

        // 一直冒泡将触发事件的节点和各父级节点都放入this.currentTargets
        while (target) {
            if (this.targets.indexOf(target) !== -1) {
                targets.unshift(target);//对targets数组向前添加触发事件的元素
            }

            target = target.parentNode;
            this.currentTargets.push(target); //对this.currentTargets数组向后添加触发事件的元素的父元素
        }

        this.startEvent = e;//开始事件
        this.startPoint = Ext.util.Point.fromEvent(e);//获取事件的坐标点
        this.lastMovePoint = null;
        this.isClick = true;//点击标志
        this.handleTargets(targets, e);
    },

	//pc上的'mousemove',移动设备上的'touchmove'的响应函数
    onTouchMove: function (e) {
	
		//如果不是Android平台
        if (!Ext.is.Android) {
            e.preventDefault();//组织默认事件
        }

		//如果开始事件为空，直接返回
        if (!this.startEvent) {
            return;
        }

		//如果是pc平台
        if (Ext.is.Desktop) {
            e.target = this.startEvent.target;
        }

		//如果事件冻结，直接返回
        if (this.isFrozen) {
            return;
        }

        var gestures = this.currentGestures,//已经开始的动作列表
            gesture,
            touch = e.changedTouches ? e.changedTouches[0] : e;

        this.lastMovePoint = Ext.util.Point.fromEvent(e);//事件后面的坐标，相对于开始触碰时的事件的坐标

		//如果事件超出了onMouseStart事件坐标半径5像素以外
        if (Ext.supports.Touch && this.isClick && !this.lastMovePoint.isWithin(this.startPoint, this.clickMoveThreshold)) {
            this.isClick = false;//点击标志设为false
        }

		//遍历已经开始的动作列表
        for (var i = 0; i < gestures.length; i++) {
		
			//如果事件被组织，直接跳出循环
            if (e.stopped) {
                break;
            }

            gesture = gestures[i];

			//如果gesture的listenForMove属性存在且为真
            if (gesture.listenForMove) {
                gesture.onTouchMove(e, touch); //gesture的onTouchMove方法
            }
        }
    },

	//pc上的'mouseend',移动设备上的'touchend'的响应函数
    onTouchEnd: function (e) {
	
		//如果是Blackberry平台，阻止默认事件
        if (Ext.is.Blackberry) {
            e.preventDefault();
        }

		//如果事件被冻结，直接返回
        if (this.isFrozen) {
            return;
        }

        var gestures = this.currentGestures.slice(0),
            ln = gestures.length,
            i, gesture, endPoint,
            needsAnotherMove = false,
            touch = e.changedTouches ? e.changedTouches[0] : e;

		//如果onTouchStart的事件坐标点存在
        if (this.startPoint) {
		
			//onTouchEnd的事件坐标点
            endPoint = Ext.util.Point.fromEvent(e);
			
			//如果onTouchMove和onTouchStart的事件坐标点的位置和onTouchEnd不同
            if (!(this.lastMovePoint || this.startPoint)['equals'](endPoint)) {
                needsAnotherMove = true;//在touch事件结束前是否先调用touch的移动方法
            }
        }

		//遍历gesture数组
        for (i = 0; i < ln; i++) {
            gesture = gestures[i];//当前gesture

			//如果事件没有被阻止且gesture的listenForEnd属性为真
            if (!e.stopped && gesture.listenForEnd) {

				//如果needsAnotherMove为true
                if (needsAnotherMove) {
                    gesture.onTouchMove(e, touch);//调用gesture对象的onTouchMove方法
                }

                gesture.onTouchEnd(e, touch);//调用gesture对象的onTouchEnd方法
            }

			//停止gesture
            this.stopGesture(gesture);
        }

		//如果点击标志为真
        if (Ext.supports.Touch && this.isClick) {
            this.isClick = false;//点击标志设为false
			//获取Ext.util.EventSimulator对象，调用该对象的fire方法，
			//创建一个新的click的Event对象，触发target上的该Event事件
            this.getEventSimulator().fire('click', this.startEvent.target, touch);
        }

        this.lastMovePoint = null;//清除onTouchEnd事件坐标
        this.followTouches = [];//清空followTouches数组（这个数组没发现有什么用）
        this.startedChangedTouch = false;//
        this.currentTargets = [];//清空触发事件的节点数组
        this.startEvent = null;//清除onTouchStart事件
        this.startPoint = null;//清除onTouchStart事件坐标
    },

    //在onTouchStart方法的结尾调用this.handleTargets(targets, e);
    handleTargets: function (targets, e) {


        var ln = targets.length,
            i;

        this.startedChangedTouch = false;
		
		//事件数组
        this.startedTouches = Ext.supports.Touch ? e.touches : [e];

        for (i = 0; i < ln; i++) {
            if (e.stopped) {//如果事件被阻止，跳出继续下一个循环
                break;
            }
			
            this.handleTarget(targets[i], e, true);//启动捕获事件型gesture对象
        }

        for (i = ln - 1; i >= 0; i--) {
            if (e.stopped) {
                break;
            }
			
            this.handleTarget(targets[i], e, false);//启动非捕获事件型gesture对象
        }

        if (this.startedChangedTouch) {
            this.followTouches = this.followTouches.concat((Ext.supports.Touch && e.targetTouches) ? Ext.toArray(e.targetTouches) : [e]);
        }
    },

    //
    handleTarget: function (target, e, capture) {
        //在Ext.cache中，找到包含target的缓存信息，在缓存信息的data对象中找到'x-gestures'键对应的值，并返回
        var gestures = Ext.Element.data(target, 'x-gestures') || [],
            ln = gestures.length,
            i, gesture;

		//遍历gestures数组
        for (i = 0; i < ln; i++) {
		
            gesture = gestures[i];//当前gesture对象
			
            if (
				//如果gesture的capture类型与参数指定的capture类型一致
                (!!gesture.capture === !!capture) &&
				//如果followTouches数组的长度小于gesture的计数值（目前只有Ext.gesture.Pinch的计数是2，其他都是1）
                (this.followTouches.length < gesture.touches) &&
				//如果是自己新建的Event（自己新建的Event对象才有targetTouches属性）被触发，且触发的事件数等于getsture计数或则是原生事件被触发
                ((Ext.supports.Touch && e.targetTouches) ? (e.targetTouches.length === gesture.touches) : true)
            ) {
                this.startedChangedTouch = true;//开始第一次触屏的意思，相对于第二根手指触屏
                this.startGesture(gesture);//开始动作

                // 默认情况下，所有gesture.listenForStart都是true
                if (gesture.listenForStart) {//如果gesture对象设置了对start的侦听
                    gesture.onTouchStart(e, e.changedTouches ? e.changedTouches[0] : e); //gesture的onTouchStart函数
                }

                if (e.stopped) {
                    break;
                }
            }
        }
    },

    //标记gesture已经开始
    startGesture: function (gesture) {
        gesture.started = true;
        this.currentGestures.push(gesture);
    },

    //停止gesture
    stopGesture: function (gesture) {
        gesture.started = false;
        this.currentGestures.remove(gesture);
    },

    //target：HtmlElement对象, eventName：事件名, listener：一个函数，传入浏览器event对象，封装成新的event对象, 
    //opitons：配置对象
    addEventListener: function (target, eventName, listener, options) {

        target = Ext.getDom(target);//获取target元素的DOM
        options = options || {};

        var targets = this.targets,

			//通过事件名ename找到对应的gesture名
            name = this.getGestureName(eventName), //return this.names && this.names[ename];

            gestures = Ext.Element.data(target, 'x-gestures'),//获取gesture数组

            gesture;

        if (!gestures) {//如果缓存中没有符合条件的gestures数组
            gestures = [];
            Ext.Element.data(target, 'x-gestures', gestures);//创建一个新数组放入缓存的指定位置
        }


        if (!name) {
            throw new Error('Trying to subscribe to unknown event ' + eventName);
        }

        //如果this.targets数组中还没有参数传来的元素，则把该元素放入this.targets数组中
        if (targets.indexOf(target) === -1) {
            this.targets.push(target);
        }

        gesture = this.get(target.id + '-' + name);//在gesture对象管理列表中找到gesture对象

        if (!gesture) {//如果取不到gesture对象，则创建一个
            gesture = this.create(Ext.apply({}, options, {
                target: target,
                type: name
            }));

            gestures.push(gesture);//将新建的gesture对象放入缓存的对应位置


        }

        gesture.addListener(eventName, listener);//给gesture对象添加事件侦听函数

		//如果
        if (this.startedChangedTouch && this.currentTargets.contains(target) && !gesture.started && !options.subsequent) {
            this.startGesture(gesture);
            if (gesture.listenForStart) {
                gesture.onTouchStart(this.startEvent, this.startedTouches[0]);
            }
        }
    },

    removeEventListener: function (target, eventName, listener) {
        target = Ext.getDom(target);

        var name = this.getGestureName(eventName),
            gestures = Ext.Element.data(target, 'x-gestures') || [],
            gesture;

        gesture = this.get(target.id + '-' + name);

        if (gesture) {
            gesture.removeListener(eventName, listener);

            for (name in gesture.listeners) {
                return;
            }

            gesture.destroy();
            gestures.remove(gesture);
            Ext.Element.data(target, 'x-gestures', gestures);
        }
    },

	//通过事件名ename找到对应的gesture名
    getGestureName: function (ename) {
        return this.names && this.names[ename];//返回后面的值
    },

    //注册gesture类
    registerType: function (type, cls) {
        var handles = cls.prototype.handles,
            i, ln;

        this.types[type] = cls;

        cls[this.typeName] = type;

        if (!handles) {
            handles = cls.prototype.handles = [type];
        }

        //names用来存放{事件名: gesture名}对象数组用来根据事件名找到gesture对象，好调用gesture对象的方法
        this.names = this.names || {};

        for (i = 0, ln = handles.length; i < ln; i++) {
            this.names[handles[i]] = type;//给this.names加入新键值对
        }
    }
});

Ext.regGesture = function() {
    return Ext.gesture.Manager.registerType.apply(Ext.gesture.Manager, arguments);
};